package com.editso.haier.service;

import com.editso.haier.bean.CommodityBean;
import com.editso.haier.dao.*;
import com.editso.haier.entity.*;
import com.editso.haier.result.Result;
import com.editso.haier.result.ResultCode;
import com.editso.haier.result.commodity.DetailsCommodity;
import com.editso.haier.util.Pair;
import com.editso.haier.util.Promise;
import com.editso.haier.util.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONArray;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.util.*;

@Service
public class CommodityService {
    private CommodityDao commodityDao;
    private TopicDao topicDao;
    private StandardsDao standardsDao;
    private SecondaryDao secondaryDao;
    private TagDao tagDao;

    @Autowired
    public void setTagDao(TagDao tagDao) {
        this.tagDao = tagDao;
    }

    @Autowired
    public void setSecondaryDao(SecondaryDao secondaryDao) {
        this.secondaryDao = secondaryDao;
    }

    @Autowired
    public void setStandardsDao(StandardsDao standardsDao) {
        this.standardsDao = standardsDao;
    }

    @Autowired
    public void setTopicDao(TopicDao topicDao) {
        this.topicDao = topicDao;
    }

    @Autowired
    public void setCommodityDao(CommodityDao commodityDao) {
        this.commodityDao = commodityDao;
    }


    public Result insertCommodity(CommodityBean commodityBean, String userId) {
        return new Promise<Commodity, Result>(callback -> {
            User user = new User(userId);
            Topic topic = topicDao.findById(commodityBean.getTopic()).orElse(null);
            if (topic == null || commodityDao.existsCommodityByName(commodityBean.getName())) {
                callback.reject(null);
            } else {
                Commodity commodity = new Commodity();
                commodity.setName(commodityBean.getName());
                commodity.setTopic(topic);
                commodity.setUser(user);
                commodity.setDescription(commodityBean.getDescription());
                commodity.setPrice(new BigDecimal(Utils.get(commodityBean.getPrice(), "0")));
                callback.resolve(commodity);
            }
        }, accept -> Result.success(), error -> Result.failure()).accept(callback -> {
            Commodity commodity = callback.get();
            for (String tag : commodityBean.getTags()) {
                commodity.getTags().add(tagDao.findByName(tag).orElse(new Tag(tag)));
            }
            for (Map<String, Object> option : commodityBean.getOptions()) {
                CommodityStandards commodityStandards = new CommodityStandards();
                CommoditySecondary commoditySecondary = new CommoditySecondary();
                commodityStandards.setCommodity(commodity);
                commoditySecondary.setCommodity(commodity);
                commoditySecondary.setTopic(commodity.getTopic());
                String standardsName = String.valueOf(option.get("key"));
                Standards standards = standardsDao.findByName(standardsName).orElse(new Standards(standardsName));
                commodityStandards.setStandards(standards);
                List<Map<String, Object>> secondaryNames = (List<Map<String, Object>>) option.get("items");
                for (Map<String, Object> item : secondaryNames) {
                    String secondaryName = String.valueOf(item.get("key"));
                    List<String> secondaryValues = (List<String>) item.get("items");
                    for (String secondaryValue : secondaryValues) {
                        Secondary secondary = secondaryDao.findByValue(secondaryValue)
                                .orElse(new Secondary(secondaryName, secondaryValue));
                        commodityStandards.setSecondary(secondary);
                        commoditySecondary.setSecondary(secondary);
                    }
                    commodity.getCommoditySecondaries().add(commoditySecondary);
                }
                commodity.getCommodityStandards().add(commodityStandards);
            }
            for (Pair<CommodityBean.AssetsOther, List<Map<String, String>>> assetsPair : commodityBean.assetsPairs()) {
                for (Map<String, String> item : assetsPair.getValue()) {
                    String absPath = Utils.joinPath(item.get("path"), item.get("fileName"));
                    commodity.getAssets().add(new Assets(absPath, assetsPair.getKey().getContentType(), assetsPair.getKey().ordinal()));
                }
            }
            commodityDao.save(commodity);
        }).get();
    }

    /**
     * 查询所有商品
     */
    public Result queryAllCommodity(Integer page, Integer size) {
        return new Promise<Set<Commodity>, Result>(callback -> {
            Set<Commodity> commodities = new HashSet<>();
            Iterable<Topic> all = topicDao.findAll();
            for (Topic topic : all) {
                commodities.addAll(topic.getCommodities());
            }
            callback.resolve(commodities);
        }, accept -> Result.success(
                DetailsCommodity.from(accept)
        ), error -> Result.failure()).get();
    }


    /**
     * 查询一个主题下的所有商品
     */
    public Result queryTopicCommodity(Integer topicId, Integer page, Integer size) {
        Topic topic = topicDao.findById(topicId).orElse(null);
        return new Promise<Topic, Result>(callback -> {
            callback.not(topic == null, topicDao.findById(topicId).orElse(null));
            callback.error(err -> Result.failure("该主题不存在!"));
            callback.accept(success -> Result.success(DetailsCommodity.from(success.getCommodities())));
        }, accept -> Result.success(), error -> Result.failure()).get();
    }

    public Result details(String id){
        return Result.promise(callback->{
            Commodity commodity = commodityDao.findById(id).orElse(null);
            callback.and(commodity != null, commodity);
            callback.accept(accept->Result.success(
                    DetailsCommodity.from(commodity, true)
            ));
        });
    }
}
